package com.example.origin.finance.trade.service.impl;


import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.example.origin.finance.dto.BaseTable;
import com.example.origin.finance.dto.XueqiuKline;
import com.example.origin.finance.dto.XueqiuQuote;
import com.example.origin.finance.enums.AnalystEnum;
import com.example.origin.finance.enums.TableNameEnum;
import com.example.origin.finance.trade.dto.Analyst;
import com.example.origin.finance.trade.dto.InfoResource;
import com.example.origin.finance.trade.dto.Trader;
import com.example.origin.finance.trade.dto.impl.BlueAnalyst;
import com.example.origin.finance.trade.dto.impl.RedAnalyst;
import com.example.origin.finance.trade.dto.impl.RedUsAnalyst;
import com.example.origin.finance.trade.service.AbstractModelService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
public class BetaModelService extends AbstractModelService {

    public void model(String nowStr, String endStr,AnalystEnum analystEnum) {
        Analyst analyst = analystEnum.getAnalyst();
        TableNameEnum klineTableNameEnum = analystEnum.getKlineTableNameEnum();
        TableNameEnum quoteTableNameEnum = analystEnum.getQuoteTableNameEnum();
        DateTime now = DateUtil.parseDate(nowStr);
        DateTime start = DateUtil.offsetWeek(now, -10);
        DateTime end = DateUtil.parseDate(endStr);
        // quote
        Query query = new Query();
        List<XueqiuQuote> xueqiuQuotes = find(query, quoteTableNameEnum);
        Map<String, XueqiuQuote> quoteMap = xueqiuQuotes.stream().collect(Collectors.toMap(BaseTable::getCode, Function.identity()));

        // kline
        query = new Query();
        query.addCriteria(Criteria.where("timestamp").gte(start).lt(end));

        List<XueqiuKline> xueqiuKlines = find(query, klineTableNameEnum);
        if (xueqiuKlines.isEmpty())return;
        filterKline(xueqiuKlines);

        Map<String, Map<String, XueqiuKline>> xueqiuKlinesMap = xueqiuKlines.stream().collect(Collectors.groupingBy(e ->
                DateUtil.formatDate(e.getTimestamp()), Collectors.toMap(BaseTable::getCode, e -> e)));
        Map<String, Map<String, XueqiuKline>> xueqiuKlinesCodeMap = xueqiuKlines.stream().collect(Collectors.groupingBy(
                BaseTable::getCode, Collectors.toMap(e ->
                        DateUtil.formatDate(e.getTimestamp()), e -> e)));
        Trader trader = new Trader();

        trader.setAnalyst(analyst);

        while (DateUtil.compare(now, end) < 0) {
            String nowDayStr = DateUtil.formatDate(now);
            Map<String, XueqiuKline> listMap = xueqiuKlinesMap.get(nowDayStr);
            if (listMap != null) {
                for (Map.Entry<String, XueqiuKline> listEntry : listMap.entrySet()) {
                    String code = listEntry.getKey();
                    XueqiuKline xueqiuKline = listEntry.getValue();
                    if (!quoteMap.containsKey(code)) {
                        continue;
                    }
                    Map<String, XueqiuKline> xueqiuKlineCodeMap = xueqiuKlinesCodeMap.get(code);

                    Map<Date,XueqiuKline> dateXueqiuKlineMap = new LinkedHashMap<>();
                    dateXueqiuKlineMap.put(now,xueqiuKline);
                    Date beforeDate = now;
                    for (int i = 0; i < 9; i++) {
                        beforeDate = beforeDate(beforeDate, xueqiuKlineCodeMap);
                        if (beforeDate==null){
                            break;
                        }
                        dateXueqiuKlineMap.put(beforeDate,xueqiuKlineCodeMap.get(DateUtil.formatDate(beforeDate)));
                    }
                    if (beforeDate==null){
                        continue;
                    }


                    InfoResource infoResource = new InfoResource();
                    infoResource.setCode(code);
                    infoResource.setTime(xueqiuKline.getTimestamp());
                    infoResource.setKline(xueqiuKline);
                    infoResource.setQuote(quoteMap.get(code));
                    infoResource.setMoreKlines(new ArrayList<>(dateXueqiuKlineMap.values()));

                    trader.getInfoResources().add(infoResource);
                    trader.buyOrSell();

                }
            }
            if (klineExist(xueqiuKlinesMap, DateUtil.formatDate(now))) {
                trader.logAsset(now, xueqiuKlinesMap.get(DateUtil.formatDate(now)));
            }
            now = DateUtil.offsetDay(now, 1);
        }
        while (!klineExist(xueqiuKlinesMap, DateUtil.formatDate(now))) {
            now = DateUtil.offsetDay(now, -1);
        }
        Map<String, XueqiuKline> klinesMap = xueqiuKlinesMap.get(DateUtil.formatDate(now));
        trader.allSell(now, klinesMap);


    }

    private static Date beforeDate(Date now, Map<String, XueqiuKline> xueqiuKlineCodeMap) {
        Date beforeDay = DateUtil.offsetDay(now, -1);
        int i = 0;
        while (!xueqiuKlineCodeMap.containsKey(DateUtil.formatDate(beforeDay))) {
            if (i++==20){
                return null;
            }
            beforeDay = DateUtil.offsetDay(beforeDay, -1);
        }
        return beforeDay;
    }


    private static boolean klineExist(Map<String, Map<String, XueqiuKline>> xueqiuKlinesMap, String nextDayStr) {
        return xueqiuKlinesMap.containsKey(nextDayStr);
    }
}
